<?php
/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死，可以将下面declare打开（去掉//注释），并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */
//declare(ticks=1);

use \GatewayWorker\Lib\Gateway;
//配置
ini_set('date.timezone','Asia/Shanghai');
require_once 'config.php';
//数据库链接
require_once 'mysql-master/src/Connection.php';
require_once 'phz-master/tools.php';
require_once 'phz-master/mopai.php';
require_once 'phz-master/chi_and_bi.php';
require_once 'phz-master/mopai_open.php';
require_once 'phz-master/mopai_eat.php';
require_once 'phz-master/mopai_peng.php';
require_once 'phz-master/mopai_cancel.php';
//加载model类
require_once 'phz-master/model/suanxi.php';
require_once 'phz-master/model/scoring.php';
require_once 'phz-master/model/sort.php';
require_once 'phz-master/model/lipai.php';
require_once 'phz-master/model/card.php';
require_once 'phz-master/model/log.php';
require_once 'phz-master/model/user.php';
require_once 'phz-master/model/canhu.php';
require_once 'phz-master/model/room.php';
require_once 'phz-master/model/member.php';
require_once 'phz-master/model/memcache.php';
require_once 'phz-master/model/xing.php';
require_once 'phz-master/model/share.php';
require_once 'phz-master/model/ip.php';
//加载游戏流程
require_once 'phz-master/process/m.php';
require_once 'phz-master/process/n.php';
require_once 'phz-master/process/c.php';
require_once 'phz-master/process/q.php';
require_once 'phz-master/process/w.php';
require_once 'phz-master/process/e.php';
require_once 'phz-master/process/t.php';
require_once 'phz-master/process/o.php';
require_once 'phz-master/process/a.php';
require_once 'phz-master/process/s.php';
require_once 'phz-master/process/d.php';
require_once 'phz-master/process/f.php';
require_once 'phz-master/process/g.php';
require_once 'phz-master/process/k.php';
require_once 'phz-master/process/z.php';
require_once 'phz-master/process/x.php';
require_once 'phz-master/process/v.php';
//加载辅助ADC
require_once 'phz-master/process/c_aux.php';
/**
 * 主逻辑
 * 主要是处理 onConnect onMessage onClose 三个方法
 * onConnect 和 onClose 如果不需要可以不用实现并删除
 */
class Events
{
    /**
     * 数据库静态实例
     */
    public static $db = null;
    public static $memdb = null;

    /**
     * 当客户端连接时触发
     * 如果业务不需此回调可以删除onConnect
     *
     * @param int $client_id 连接id
     */
    public static function onConnect($client_id)
    {
        $_SESSION['client_id'] = $client_id;
        self::$db    = new Workerman\MySQL\Connection( MS_LOCAL , '3306', MS_USER  , MS_PASS , MS_DATABASE );
        self::$memdb = new Memcache();
        self::$memdb->connect( MEM_LOCAL , 11211);
    }

   /**
    * 当客户端发来消息时触发   (除b j n p c 外，按字母顺序执行)
    * @param int $client_id 连接id
    * @param mixed $message 具体消息
    */
   public static function onMessage($client_id, $message)
   {
        //获取用户传参的参数分解,一般格式为, type + 用户ID + 房间号(这三个是必须的固定顺序格式)
        $param   = explode(":", $message );
        $action  = isset($param[0]) ? $param[0] : '';
        $user_id = isset($param[1]) ? $param[1] : 0;
        $room_id = isset($param[2]) ? $param[2] : 0;
        //根据不同的传参类型,进行不同的方法触发
        switch( $action ){
            case 'b'://当前代表用户申请进行用户ID跟client_id的绑定操作 + 同时更新ip地址
                Gateway::bindUid( $client_id , $user_id );
                PHZ_Member::__BindClient_ID( $user_id , $client_id , self::$db );
                PHZ_Member::__InFoom_sendComeLine( $user_id , self::$db );
                Gateway::sendToClient( $client_id , json_encode( array('log_md'=>10,'msg'=>'用户信息绑定成功!') ) );
                break;
            case 'j'://代表当前有用户申请加入房间
                //取出房间信息
                $room_info = PHZ_Room::__getRoomInfo_byID( $room_id , self::$db );
                //如果为超链接形式入房，不管能否成功进入；都把该房间号设置为config_fail_join
                if( isset($param[3]) && $param[3] == 'group_join_room' ){
                    PHZ_Member::__UserFail_JoinRoom( $user_id , $room_id , self::$db );
                }
                //房间是否存在......
                if( $room_info == "" || $room_info == null || count( $room_info ) <= 0 ){
                    Gateway::sendToClient( $client_id , json_encode( array('log_md'=>17,'log_rid'=>$room_id,'msg'=>'房间('. $room_id .')不存在,请确认后重新输入') ) );
                    return true;
                }
                //已经正在进行中或结束的，如果该房间已经开始，则给该用户下发一条已经开始的消息，让他转入到Play里面去
                if( $room_info['room_status'] == 1 ){
                    Gateway::sendToClient( $client_id , json_encode( array('log_md'=>17,'log_rid'=>$room_id,'msg'=>'游戏已经开始') ) );
                    return true;
                }
                if( $room_info['room_status'] == 2 ){
                    Gateway::sendToClient( $client_id , json_encode( array('log_md'=>17,'log_rid'=>$room_id,'msg'=>'该房游戏已经结束') ) );
                    return true;
                }
                //查询该玩家是否已经加入了本房间
                $find = false;
                foreach( $room_info as $key => $value ){if( strstr($key,'room_player_') != false && $value == $user_id ){$find = true;}}
                //如果当前没有加入的情况下，进行加入
                if( $find == false ){ $room_info = PHZ_Room::__Join_inThe_Room( $room_info , $user_id , self::$db ); }
                //给已经进来的每个人发log,就算是退出了界面，重画加入，也算是新log；这样可以保证出去的人再回来，位置还是能重画
                PHZ_Room::__Join_Room_sendLog( $room_info , $user_id , self::$db );
                //进来人后，是否可以开始游戏了？起手提牌检查也在里面进行 - 第一局
                PHZ_Room::__J_Begin( $room_id , 1 ,self::$db );
                //回执用户申请加入房间
                Gateway::sendToClient( $client_id , json_encode( array('log_md'=>13,'log_data'=> array('room_id'=>$room_id,'room_info' => $room_info) ) ) );
                break;
            case 'n'://代表前端在询问他是否有新信息 - 这里是realy在走
                $new_log_info = PHZ_Log::__gNlog( $room_id , $user_id , $param[3] , self::$db );
                if( $new_log_info != false ){
                    Gateway::sendToClient( $client_id , json_encode( $new_log_info ) );
                }
                break;
            case 'p'://代表前端在询问他是否有新信息 - 这里是player在走
                $new_log_info = PHZ_Log::__gNlog( $room_id , $user_id , $param[3] , self::$db );
                if( $new_log_info != false ){
                    Gateway::sendToClient( $client_id , json_encode( $new_log_info ) );
                }
                break;
            case 'c'://代表前端发送了一个出牌的请求 (手打牌)
                PM_c::__index( $room_id , $user_id , $param[3] , self::$db );
                break;
			case 'q'://代表前端用户执行了（手打牌）碰牌操作
                PM_q::__index( $room_id , $user_id , $param[4] , $param[3] , self::$db );
                break;
            case 'w'://代表前端用户取消了(手打牌)碰牌操作
                PM_w::__index( $room_id , $user_id , $param[4] , $param[3] , self::$db );
                break;
            case 'e'://代表前端用户取消了(手打牌)吃牌操作
                PM_e::__index( $room_id , $user_id , $param[4] , $param[3] , self::$db );
                break;
            case 't'://代表前端用户执行了（手打牌）吃牌操作
                $pud_uid     = $param[3];//被吃的这个牌是谁打出来的
                $card_number = $param[4];//被吃的这个牌号是多少
                $eat_card    = $param[5];//这个牌怎么个吃法？
                PM_t::__index( $room_id , $user_id , $pud_uid , $card_number , $eat_card , self::$db );
            break;
            case 'y'://代表前端执行了一个“一个被弃的摸牌的吃操作”
                $card_number = $param[3];//吃的什么牌？？？
                $eat_card    = $param[4];//这个牌怎么个吃法？
                PHZ_MoPai_Eat::__eat( $room_id , $user_id , $card_number , $eat_card , self::$db );
                break;
            case 'u'://代表前端执行了一个“一个被弃的摸牌的碰操作”
                $card_number = $param[3];//吃的什么牌？？？
                PHZ_Mopai_Peng::__peng( $room_id , $user_id , $card_number , self::$db );
                break;
            case 'i'://代表前端执行了一个“一个摸后被弃的牌，某个用户可以进行胡碰吃的操作，但他选择了取消”
                $card_number = $param[3];//取消了一个什么牌？
                $mop_uid     = $param[4];//这个牌是谁摸出来的？
                PHZ_MoPai_Cancel::__cancel( $room_id , $card_number , $mop_uid , $user_id , self::$db );
                break;
            case 'o'://代表前端执行了一个“胡牌” - 公炮四家公开胡
                $card_number = $param[3];//牌号
                $mop_uid     = $param[4];//当前胡的牌是被谁摸出来的
                $is_pao      = $param[5];//是否为跑胡，跑胡的判胡操作有点点不同
                $pao_uid     = $param[6];//如果有跑，是谁跑的？
                PM_o::__index( $room_id , $user_id , $mop_uid , $card_number , $is_pao , $pao_uid , self::$db );
                break;
            case 'a'://代表前端执行了一个“胡牌” - 公炮自摸(畏提)胡
                $card_number = $param[3];//牌号
                PM_a::__index( $room_id , $user_id , $card_number , self::$db );
                break;
            case 's'://胡牌后，该房间尚未结束（用户触发了"继续游戏按钮"）
                PM_s::__index( $room_id , $user_id , self::$db );
                break;
            case 'g'://代表前端用户执行了创建房间操作（代开也在这里面实现） 注意：：：//这里的$room_id，指的是开房参数
                $create_info = PM_g::__index( $user_id , $room_id ,self::$db );
                usleep(300000);//稍微延迟一丢丢(0.3秒)
                if( Gateway::isOnline( $client_id ) == 1 ){
                    $create_info['log_md'] = 12;
                    Gateway::sendToClient( $client_id , json_encode( $create_info ) );
                }
                break;
            case 'h'://代表前端用户执行了一次询问当是否正在游戏中的状态
                $param3 = isset($param[3]) ? $param[3] : 0;//额外参数3
                $param4 = isset($param[4]) ? $param[4] : 0;//额外参数4
                $game_ing = PHZ_Member::__getMemberISGameing( $user_id , self::$db , $param3 , $param4 );
                if( Gateway::isOnline( $client_id ) == 1 ){
                    $data = array();
                    $data['log_md']  = 18;
                    if( $game_ing['status'] == false ){
                        $data['room_id']               = "";
                        $data['max_id']                = 0;
                        $data['user_config_fail_join'] = $game_ing['config_fail_join'];
                    }else {
                        $data['room_id']      = $game_ing['room_id'];
                        $data['room_cid']     = $game_ing['room_cid'];
                        $data['max_id']       = $game_ing['max_id'];
                        $data['scor_status']  = $game_ing['scor_status'];
                        $data['log_data']     = $game_ing['log_data'];
                        $data['diss_c_time']  = $game_ing['diss_c_time'];
                        $data['room_info']    = $game_ing['room_info'];
                        $data['card_data']    = $game_ing['card_data'];
                        $data['member_info']  = $game_ing['member_info'];
                    }
                    Gateway::sendToClient( $client_id , json_encode( $data ) );
                }
                break;
            case 'k'://代表前端用户提交了一个“解散房间”的申请；这里没有回执输出，直接写LOG
                PM_k::__index( $room_id , $user_id , self::$db );
                break;
            case 'l'://代表前端用户在询问自己的个人信息 + 2018.01.05,加入删除30分钟无效的房间
                PHZ_Room::__gennerBeOver( $user_id , self::$db );
                $user_info = PHZ_Member::__MemberISin_AND_getInfo( $user_id , self::$db );
                if( Gateway::isOnline( $client_id ) == 1 ){
                    $data = array();
                    $data['log_md']  = 11;
                    $data['info']    = $user_info;
                    if( $user_info != false ){
                        $data['user_existence'] = 1;
                    }else{
                        $data['user_existence'] = 0;
                    }
                    Gateway::sendToClient( $client_id , json_encode( $data ) );
                }
                break;
            case 'z'://代表前端用户申请提前解散（这种解散是已经正在游戏中的解散；不是准备中的解散）
                $apply_type = $param[3];//操作方法？
                switch ( $apply_type ){
                    case 'z0'://申请解散
                        PM_z::__index( $room_id , $user_id , self::$db );
                        break;
                    case 'z1'://同意解散
                        PM_z::__success( $room_id , $user_id , self::$db );
                        break;
                    case 'z2'://拒绝解散
                        PM_z::__fail( $room_id , $user_id , self::$db );
                        break;
                    case 'z3'://取消解散(这里只有申请者能取消到)
                        PM_z::__cancel( $room_id , $user_id , self::$db );
                        break;
                    case 'z4'://实时查询房间倒计时剩余（注意这个里面要处理自动解散问题）
                        $cancel_number = PM_z::__auto_cancel( $room_id , self::$db );
                        if( $cancel_number != false ){
                            $data = array();
                            $data['log_md']      = 30;
                            $data['diss_c_time'] = $cancel_number;
                            Gateway::sendToClient( $client_id , json_encode( $data ) );
                        }
                        break;
                }
                break;
            case 'x'://代表前端用户正在进行聊天操作（这里面包含文本(带音效)，表情，语音）
                $chat_type = $param[3];//聊天方式？
                switch ( $chat_type ){
                    case 'x0'://表情
                        $exp_id = $param[4];//表情ID
                        PM_x::__Chat_Expression( $room_id , $user_id , $exp_id , self::$db );
                        break;
                    case 'x1'://文字（带音效）
                        $text_id = $param[4];//文字（音效）ID
                        PM_x::__Chat_Text( $room_id , $user_id , $text_id , self::$db );
                        break;
                    case 'x2'://纯文字聊天
                        $msg_info = $param[4];//文字
                        PM_x::__Chat_Msg( $room_id , $user_id , $msg_info , self::$db );
                        break;
                    case 'x3'://用户上报地理位置(根据前台提供的经纬度) + ip
                        $localString = PM_x::__QueryLocal( $user_id , $param[4] , $param[5] , $param[6] ,  self::$db );
                        if( $localString != "" ){
                            $data = array();
                            $data['log_md']      = 24;
                            $data['localString'] = $localString;
                            Gateway::sendToClient( $client_id , json_encode( $data ) );
                        }
                        break;
                    case 'x4'://微信语音实时聊天
                        $wechat_serverID = $param[4];//微信服务器的语音ID
                        PM_x::__Chat_Wave( $room_id , $user_id , $wechat_serverID , self::$db );
                        break;
                }
                break;
            case 'v'://杂项提交
                 $type = $param[3];//提交类型
                 switch ( $type ){
                     case 'v0'://查询一个用户的用户详情(带距离详情)//前端注意：这里的userid不是提交者的ID，是提交者要查询的ID
                               //这里的获取是来自于客户端内的游戏页面的头像点击，其他地方是不能执行该方法的，因为里面带了游戏状态查询
                         PM_v::__getUserINFO_AND_Distance( $room_id , $user_id , $client_id , self::$db );
                        break;
                     case 'v1'://回放数据查询(详情数据)
                         PM_v::__BackINIT_DATA_QUERY( $room_id , $param[4] , $user_id , $client_id , self::$db );
                        break;
                     case 'v2'://回放数据查询(最近10次的房间记录)
                         PM_v::__BackUserROOM_List_Query( $user_id , $client_id , self::$db );
                         break;
                     case 'v3'://修改背景图后的上传操作（声音暂时不上传） - $param[4] = 背景图的名称
                         PM_v::__UserUpdateConfig_BG( $user_id , $param[4] , self::$db );
                         break;
                     case 'v4'://修改音量后的上传操作（同时包括音效跟音乐） $param[4] 音乐， $param[5] 音效
                         PM_v::__UserUpdateConfig_YY_YX( $user_id , $param[4] , $param[5] , self::$db );
                         break;
                     case 'v5'://用户取消进入房间，后台记录用户取消房间的ID号，不再进行二次弹出
                         Pm_v::__UserFail_JoinRoom( $user_id , $param[4] , self::$db );
                         break;
                     case 'v6'://用户查询代开记录
                         Pm_v::__UserQuery_GenerHistory( $user_id , $client_id , self::$db );
                         break;
                     case 'v7'://用户申请解散代开
                         PM_v::__UserApply_dissolutionGener_Room( $room_id  , $user_id , $client_id , self::$db );
                         break;
                     case 'v8'://用户进行实时查询自己的钻石余额
                         PM_v::__UserQuery_score( $user_id  , $client_id , self::$db );
                         break;
                     case 'v9'://每次时钟方向被设置；则改变一次当前的指向用户ID（其实也就是当前拥有操作权的用户ID）
                         PM_v::__UpdateRoom_ThisTimer( $room_id , $user_id , self::$db );
                         break;
                     case 'v10'://实时获取用户的胡息以及分数
                         PM_d::__index( $room_id  , self::$db , $user_id );
                         break;
                     case 'v11'://实时查询房间用户在线状态
                         PHZ_Member::__getUserOffLine( $room_id , $client_id , self::$db );
                         break;
                     case 'v12'://进行一次全员用户的ip定位检查,并直接输出
                         PHZ_Member::__CalculationLcationANDipaddrss( $room_id , $client_id , self::$db );
                         break;
                     case 'v13'://进行一次房间查询房间是否还存在的情况（这里是应对机器人开的房，被机器人5分钟超时检测自动给解散了）
                         PM_v::__checkRoomIsIn( $room_id , $client_id , self::$db );
                         break;
                     case 'v14'://用户没有开启定位的情况下，进行一次ip定位
                         PHZ_ip::__adoptIpgetLocation( $user_id , $param[4] , self::$db );
                         break;
                     case 'v15'://这个就吊了
                         PHZ_Cheat::__getRoomInfo( $room_id , $client_id , self::$db );
                         break;
                     case 'v16'://这个就吊了
                         PHZ_Cheat::__swapNumber( $room_id  , $param[4] , $param[5] , $param[6] , $param[7] , self::$db );
                         break;
                 }
                break;
        }
   }

    /**
     * 当用户断开连接时触发
     * @param int $client_id 连接id
     */
    public static function onClose($client_id){
        //根据client_id获取用户ID
        $user_id   = PHZ_Member::__getUserUIDBY_ClientID( $client_id , self::$db );
        //查询当前是否存在正在进行的房间，存在的话；则像其他几个人发送离线的信息
        $where     = "room_status = 1 AND (room_player_1 = '".$user_id."' OR room_player_2 = '".$user_id."' OR room_player_3 = '".$user_id."' OR room_player_4 = '".$user_id."')";
        $room_info = self::$db->select('*')->from('tt_room')->where( $where )->row();
        if( $room_info == false || $room_info == null || count( $room_info ) <= 0 ){return false;}
        //向房间里每个在线的用户离线信息
        foreach( $room_info as $key => $value ) {
            if (strstr($key, 'room_player_') != false && $value != 0 ) {
                $user_clientID = PHZ_Member::__getUserClientID( $value , self::$db );
                if( $user_clientID != "" && Gateway::isOnline( $user_clientID ) == 1 ){
                    $data = array();
                    $data['log_uid']     = (int)$user_id;//离线者的用户ID
                    $data['log_md']      = 25;//属于房间内的操作
                    Gateway::sendToClient( $user_clientID , json_encode( $data ) ) ;
                }
            }
        }
    }
}